package com.example.gustavo.hello;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.AsyncTaskLoader;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.text.StaticLayout;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.RemoteViews;
import android.widget.TextView;

import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.avos.avoscloud.AVOSCloud;
import com.avos.avoscloud.AVObject;
import com.example.gustavo.hello.model.ArrayObj;
import com.example.gustavo.hello.model.ParamObj;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.RequestParams;
import com.loopj.android.http.TextHttpResponseHandler;
import com.squareup.okhttp.OkHttpClient;
import com.tictactec.ta.lib.Core;
import com.tictactec.ta.lib.MInteger;
import com.tictactec.ta.lib.RetCode;

import org.apache.http.Header;
import org.jose4j.jwk.JsonWebKey;
import org.jose4j.jwk.JsonWebKeySet;
import org.jose4j.jwk.OctJwkGenerator;
import org.jose4j.jwk.OctetSequenceJsonWebKey;
import org.jose4j.jwk.RsaJsonWebKey;
import org.jose4j.jwk.RsaJwkGenerator;
import org.jose4j.jws.AlgorithmIdentifiers;
import org.jose4j.jws.HmacUsingShaAlgorithm;
import org.jose4j.jws.JsonWebSignature;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.InvalidJwtException;
import org.jose4j.jwt.consumer.JwtConsumer;
import org.jose4j.jwt.consumer.JwtConsumerBuilder;
import org.jose4j.keys.HmacKey;
import org.jose4j.lang.ByteUtil;
import org.jose4j.lang.JoseException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;


/**
 * Created by gustavo on 2015/1/21.
 */
public class Test {


    private static final String TAG = "test";

    public static void main(String[] args) throws Exception {


    }

    private void testException(int n){


    }

    public static void testJWT() throws JoseException {

        HmacUsingShaAlgorithm.HmacSha256 hsKey = new HmacUsingShaAlgorithm.HmacSha256();

//        Map<String, Object> map = new HashMap<>();
//        map.put(JsonWebKey.KEY_TYPE_PARAMETER, OctetSequenceJsonWebKey.KEY_TYPE);
//        map.put(OctetSequenceJsonWebKey.KEY_VALUE_MEMBER_NAME, .toString());
//
//        JsonWebKey jsonWebKey = JsonWebKey.Factory.newJwk(map);

        OctetSequenceJsonWebKey octetSequenceJsonWebKey = OctJwkGenerator.generateJwk(256);
        octetSequenceJsonWebKey.setKeyId("weisd");

        // Create the Claims, which will be the content of the JWT
        JwtClaims claims = new JwtClaims();
        claims.setIssuer("Issuer");  // who creates the token and signs it
        claims.setAudience("Audience"); // to whom the token is intended to be sent
        claims.setExpirationTimeMinutesInTheFuture(10); // time when the token will expire (10 minutes from now)
        claims.setGeneratedJwtId(); // a unique identifier for the token
        claims.setIssuedAtToNow();  // when the token was issued/created (now)
        claims.setNotBeforeMinutesInThePast(2); // time before which the token is not yet valid (2 minutes ago)
        claims.setSubject("subject"); // the subject/principal is whom the token is about
        claims.setClaim("email","mail@example.com"); // additional claims/attributes about the subject can be added
        List<String> groups = Arrays.asList("group-one", "other-group", "group-three");
        claims.setStringListClaim("groups", groups); // multi-valued claims work too and will end up as a JSON array

        // A JWT is a JWS and/or a JWE with JSON claims as the payload.
        // In this example it is a JWS so we create a JsonWebSignature object.
        JsonWebSignature jws = new JsonWebSignature();

        // The payload of the JWS is JSON content of the JWT Claims
        jws.setPayload(claims.toJson());

        // The JWT is signed using the private key
        jws.setKey(octetSequenceJsonWebKey.getKey());

        // Set the Key ID (kid) header because it's just the polite thing to do.
        // We only have one key in this example but a using a Key ID helps
        // facilitate a smooth key rollover process
        jws.setKeyIdHeaderValue(octetSequenceJsonWebKey.getKeyId());

        // Set the signature algorithm on the JWT/JWS that will integrity protect the claims
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);

        // Sign the JWS and produce the compact serialization or the complete JWT/JWS
        // representation, which is a string consisting of three dot ('.') separated
        // base64url-encoded parts in the form Header.Payload.Signature
        // If you wanted to encrypt it, you can simply set this jwt as the payload
        // of a JsonWebEncryption object and set the cty (Content Type) header to "jwt".
        String jwt = jws.getCompactSerialization();


        // Now you can do something with the JWT. Like send it to some other party
        // over the clouds and through the interwebs.
        System.out.println("JWT: " + jwt);


        // Use JwtConsumerBuilder to construct an appropriate JwtConsumer, which will
        // be used to validate and process the JWT.
        // The specific validation requirements for a JWT are context dependent, however,
        // it typically advisable to require a expiration time, a trusted issuer, and
        // and audience that identifies your system as the intended recipient.
        // If the JWT is encrypted too, you need only provide a decryption key or
        // decryption key resolver to the builder.
        JwtConsumer jwtConsumer = new JwtConsumerBuilder()
                .setRequireExpirationTime() // the JWT must have an expiration time
                .setAllowedClockSkewInSeconds(30) // allow some leeway in validating time based claims to account for clock skew
                .setRequireSubject() // the JWT must have a subject claim
                .setExpectedIssuer("Issuer") // whom the JWT needs to have been issued by
                .setExpectedAudience("Audience") // to whom the JWT is intended for
                .setVerificationKey(octetSequenceJsonWebKey.getKey()) // verify the signature with the public key
                .build(); // create the JwtConsumer instance

        try
        {
            //  Validate the JWT and process it to the Claims
            JwtClaims jwtClaims = jwtConsumer.processToClaims(jwt);
            System.out.println("JWT validation succeeded! " + jwtClaims);
        }
        catch (InvalidJwtException e)
        {
            // InvalidJwtException will be thrown, if the JWT failed processing or validation in anyway.
            // Hopefully with meaningful explanations(s) about what went wrong.
            System.out.println("Invalid JWT! " + e);
        }
    }

    /**
     * gson
     * @param str
     * @param clazz
     * @param <E>
     * @return
     * @throws Exception
     */
    public static <E> ArrayList<E> fromJson(String str, Class<E> clazz) throws Exception {

        Gson gson = new Gson();
        ArrayList<E> arrayList = gson.fromJson(str, getGenToken(List.class, clazz).getType());

        return arrayList;
    }

    static TypeToken<?> getGenToken(final Class<?> raw, final Class<?> gen) throws Exception {
//        Constructor<ParameterizedTypeImpl> constr = ParameterizedTypeImpl.class.getDeclaredConstructor(Class.class, Type[].class, Type.class);
//        constr.setAccessible(true);
//        ParameterizedTypeImpl paramType = constr.newInstance(raw, new Type[]{gen}, null);

        ParameterizedTypeImpl paramType = ParameterizedTypeImpl.make(raw, new Type[]{gen}, null);
        return TypeToken.get(paramType);
    }

    static final Observable.Transformer schedulersTransformer = new  Observable.Transformer() {
        @Override public Object call(Object observable) {
            return ((Observable)  observable).subscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread());
        }
    };

    public static void arraysChangeArray(){

        List<TestObj> list = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            TestObj testObj = new TestObj();
            testObj.setName("name" + i);
            list.add(testObj);

            System.out.println("test= " + testObj.getName() + " /" + testObj);

        }

        List<Object> list1 = new ArrayList<>();
        list1.addAll(list);

        for (Object obj : list1) {
            TestObj testObj = (TestObj) obj;
            System.out.println("testObj = " + testObj.getName() + " /" + testObj);
            testObj.setName("change");
        }

        for (TestObj testObj : list) {
            System.out.println("testObj = " + testObj.getName());
        }
    }

    public <T extends View> T get(Context context){
        View view = new View(context);
        return (T)view;
    }

    public TextView getId(Context context){
        return get(context);
    }

    public void testst(Context context){
        getId(context).setText("ll");

    }


    class M extends ItemTouchHelper{

        /**
         * Creates an ItemTouchHelper that will work with the given Callback.
         * <p>
         * You can attach ItemTouchHelper to a RecyclerView via
         * {@link #attachToRecyclerView(RecyclerView)}. Upon attaching, it will add an item decoration,
         * an onItemTouchListener and a Child attach / detach listener to the RecyclerView.
         *
         * @param callback The Callback which controls the behavior of this touch helper.
         */
        public M(Callback callback) {
            super(callback);
        }
    }

    private static void rxTest(){

        Observable.just("hello","world")
                .map(new Func1<String, String>() {
                    @Override
                    public String call(String s) {

                        return s + " me";
                    }
                })
                .subscribe(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        System.out.println("print " + s);
                    }
                });
    }



    private static void arrayCopy(){

        int[] a = {0,1,2,3,4,5,6,7,8,9};
        int[] b = {10,11,12,13};

        System.arraycopy(b, 0, a, 0, b.length);


        for (int i : a){
            System.out.println("i = " + i);
        }

    }

    private void testRemoteViews(Context context){

        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.activity_crop_image);
        remoteViews.setImageViewResource(R.id.iv_center, R.drawable.ic_launcher);

    }
    private static void forTest() {

        RequestParams params = new RequestParams();
        params.put("acode", "sh600519");
        params.put("code", "600519");

        List<ParamObj> list = new ArrayList<>();
        list.add(new ParamObj("adfs", "dfhs"));
        list.add(new ParamObj("code", "dfhs"));
        list.add(new ParamObj("3sdf", "dfhs"));
        list.add(new ParamObj("adfs", "dfhs"));
        list.add(new ParamObj("code", "dfhs"));
        list.add(new ParamObj("3sdf", "dfhs"));
        list.add(new ParamObj("adfs", "dfhs"));
        list.add(new ParamObj("code", "dfhs"));
        list.add(new ParamObj("3sdf", "dfhs"));
        list.add(new ParamObj("adfs", "dfhs"));
        list.add(new ParamObj("code", "dfhs"));
        list.add(new ParamObj("3sdf", "dfhs"));
        list.add(new ParamObj("adfs", "dfhs"));
        list.add(new ParamObj("code", "dfhs"));
        list.add(new ParamObj("3sdf", "dfhs"));
        list.add(new ParamObj("adfs", "dfhs"));
        list.add(new ParamObj("code", "dfhs"));
        list.add(new ParamObj("3sdf", "dfhs"));

        Collections.sort(list);

        StringBuilder sb = new StringBuilder();
        long l = System.nanoTime();
        for (ParamObj s : list) {
            sb.append(s.name).append("=").append(s.value.toString()).append("&");
        }
        System.out.println("for coast = " + (System.nanoTime() - l));
        sb.delete(sb.length() - 1, sb.length());

        System.out.println("sb = " + sb.toString());


        long l1 = System.nanoTime();
        for (int i = 0; i < list.size(); i++) {
            ParamObj paramObj = list.get(i);
            sb.append(paramObj.name).append("=").append(paramObj.value.toString()).append("&");
        }
        System.out.println("for1 coast = " + (System.nanoTime() - l1));
    }


    private static void addDBBlock() {


        String json = "{'code':200,'data':{'2015-06-03':" +
                "[{'id':70,'strategy_id':'10000660830','stkname':'???ι??'," +
                "'stkcode':'sh600621','code_no':'600621','fmlprice':'4.69'," +
                "'fmltime':'17:45:52','fmlname':'????1??','date':'2015-06-03','up':0,'down':0," +
                "'createdAt':'2015-06-03T17:45:52+08:00','updatedAt':'2015-06-03T17:45:52+08:00'}" +
                ",{'id':69,'strategy_id':'10000660830','stkname':'?????','stkcode':'sh600600','code_no':'600600','fmlprice':'5.15','fmltime':'17:45:44','fmlname':'????1??','date':'2015-06-03','up':0,'down':0,'createdAt':'2015-06-03T17:45:44+08:00','updatedAt':'2015-06-03T17:45:44+08:00'},{'id':68,'strategy_id':'10000660830','stkname':'???????','stkcode':'sh600601','code_no':'600601','fmlprice':'6.87','fmltime':'17:45:36','fmlname':'????1??','date':'2015-06-03','up':0,'down':0,'createdAt':'2015-06-03T17:45:36+08:00','updatedAt':'2015-06-03T17:45:36+08:00'},{'id':67,'strategy_id':'10000660830','stkname':'??????','stkcode':'sh600609','code_no':'600609','fmlprice':'6.05','fmltime':'17:45:28','fmlname':'????1??','date':'2015-06-03','up':0,'down':0,'createdAt':'2015-06-03T17:45:28+08:00','updatedAt':'2015-06-03T17:45:28+08:00'}]},'message':'ok','status':'ok'}";

        String json1 = "{" +
                "  'code': 200," +
                "  'data':[" +
                "            {" +
                "                'time': '2015??06??08??'," +
                "                'list': [" +
                "                    {" +
                "                        'name': '????????'," +
                "                        'code': 'sh600104'," +
                "                        'n_code': '600104'," +
                "                        'time': '14:49'" +
                "                    }," +
                "    {" +
                "                        'name': '????????'," +
                "                        'code': 'sh600104'," +
                "                        'n_code': '600104'," +
                "                        'time': '14:49'" +
                "                    }" +
                "                ]" +
                "            }," +
                "    {" +
                "                'time': '2015??06??08??'," +
                "                'list': [" +
                "                    {" +
                "                        'name': '????????'," +
                "                        'code': 'sh600104'," +
                "                        'n_code': '600104'," +
                "                        'time': '14:49'" +
                "                    }," +
                "    {" +
                "                        'name': '????????'," +
                "                        'code': 'sh600104'," +
                "                        'n_code': '600104'," +
                "                        'time': '14:49'" +
                "                    }" +
                "                ]" +
                "            }" +
                "        ]," +
                "  'message': 'ok'," +
                "  'status': 'ok'" +
                "}";
        Gson gson = new Gson();

        long l = System.currentTimeMillis();
        MapJsonObj mapJsonObj = gson.fromJson(json, MapJsonObj.class);
        System.out.println("coast = " + (System.currentTimeMillis() - l));
        System.out.println("mapJsonObj = " + mapJsonObj);

        Map<String, ArrayList<Entity>> data = mapJsonObj.data;
        for (String s : data.keySet()) {
            System.out.println("s = " + s + " / " + data.get(s));
        }


    }

    class ListJsonObj {

        /**
         * code : 200
         * data : [{"time":"2015??06??08??","list":[{"n_code":"600104","code":"sh600104","name":"????????","time":"14:49"},{"n_code":"600104","code":"sh600104","name":"????????","time":"14:49"}]},{"time":"2015??06??08??","list":[{"n_code":"600104","code":"sh600104","name":"????????","time":"14:49"},{"n_code":"600104","code":"sh600104","name":"????????","time":"14:49"}]}]
         * message : ok
         * status : ok
         */
        public int code;
        public List<DataEntity> data;
        public String message;
        public String status;

        public class DataEntity {
            /**
             * time : 2015??06??08??
             * list : [{"n_code":"600104","code":"sh600104","name":"????????","time":"14:49"},{"n_code":"600104","code":"sh600104","name":"????????","time":"14:49"}]
             */
            public String time;
            public List<ListEntity> list;

            public class ListEntity {
                /**
                 * n_code : 600104
                 * code : sh600104
                 * name : ????????
                 * time : 14:49
                 */
                public String n_code;
                public String code;
                public String name;
                public String time;
            }
        }
    }

    class MapJsonObj {
        public int code;
        public Map<String, ArrayList<Entity>> data;
        public String message;
        public String status;

        @Override
        public String toString() {
            return "MapJsonObj{" +
                    "code=" + code +
                    ", data=" + data +
                    ", message='" + message + '\'' +
                    ", status='" + status + '\'' +
                    '}';
        }
    }

    class Entity {


        /**
         * date : 2015-06-03
         * stkname : ???ι??
         * stkcode : sh600621
         * down : 0
         * fmlprice : 4.69
         * code_no : 600621
         * fmlname : ????1??
         * createdAt : 2015-06-03T17:45:52+08:00
         * fmltime : 17:45:52
         * strategy_id : 10000660830
         * id : 70
         * up : 0
         * updatedAt : 2015-06-03T17:45:52+08:00
         */
        public String date;
        public String stkname;
        public String stkcode;
        public int down;
        public String fmlprice;
        public String code_no;
        public String fmlname;
        public String createdAt;
        public String fmltime;
        public String strategy_id;
        public int id;
        public int up;
        public String updatedAt;

        @Override
        public String toString() {
            return "Entity{" +
                    "date='" + date + '\'' +
                    ", stkname='" + stkname + '\'' +
                    ", stkcode='" + stkcode + '\'' +
                    ", down=" + down +
                    ", fmlprice='" + fmlprice + '\'' +
                    ", code_no='" + code_no + '\'' +
                    ", fmlname='" + fmlname + '\'' +
                    ", createdAt='" + createdAt + '\'' +
                    ", fmltime='" + fmltime + '\'' +
                    ", strategy_id='" + strategy_id + '\'' +
                    ", id=" + id +
                    ", up=" + up +
                    ", updatedAt='" + updatedAt + '\'' +
                    '}';
        }
    }

    private static void collectionOperate() {


        List<Integer> aList = new ArrayList<>();
        List<Integer> bList = new ArrayList<>();

        aList.add(1);
        aList.add(2);
        aList.add(3);

        bList.add(2);
        bList.add(3);
        bList.add(4);

        boolean b = aList.retainAll(bList);
//        boolean b1 = aList.removeAll(bList);
        for (Integer integer : aList) {
            System.out.println("integer = " + integer);
        }

    }

    private static void doubleArrayJson() {
        int[] num = {1, 2, 3};
        int[][] nums = new int[2][2];
        nums[0] = num;
        nums[1] = num;


        TestObj testObj = new TestObj();
        testObj.setName("name");
        testObj.setAge("52");

        Gson gson = new Gson();
        String s = gson.toJson(nums);
        System.out.println("s = " + s);

        String json = "{'data' : [[1,2,3],[1,2,3]]}";
        ArrayObj arrayObj = gson.fromJson(json, ArrayObj.class);


        for (List<Integer> integers : arrayObj.data) {
            for (Integer integer : integers) {
                System.out.println("integer = " + integer);
            }
        }

    }

    static class TestObj {

        String name;
        String age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAge() {
            return age;
        }

        public void setAge(String age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "TestObj{" +
                    "name='" + name + '\'' +
                    ", age='" + age + '\'' +
                    '}';
        }
    }


    public void getUrl(Context context) {

//        AutoScrollHelper

        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        PendingIntent intent = PendingIntent.getService(context, 0, new Intent(), 0);
        alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, 2000, intent);


    }

    public void message(Context context) {

        new AsyncTaskLoader<String>(context) {
            @Override
            public String loadInBackground() {


                return "";
            }
        };


        int maxValue = Integer.MAX_VALUE;

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {


            }
        }, 2000, 1000);
        timer.cancel();


    }

    public void handler() {
        //HandlerThread ????  ?????????Handler???????
        String name = Thread.currentThread().getName();
        System.out.println("name = " + name);

        HandlerThread handlerThread = new HandlerThread("other_thread");
        handlerThread.start();

        Handler handler = new Handler(handlerThread.getLooper()) {

            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);

                boolean isMain = Looper.myLooper() == Looper.getMainLooper();
                System.out.println("isMain = " + isMain + " name=" + Thread.currentThread().getName());
            }
        };


        handler.sendEmptyMessage(0);
        System.out.println(" handler send msg");

    }

    public static void asyncHttp(final Context context) {
        final String url = "http://www.baidu.com";
        final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();

        //????????е???ba
        new Thread() {
            @Override
            public void run() {
                super.run();


                AsyncHttpClient client = new AsyncHttpClient();
                String url = "http://www.baidu.com";
                Looper.prepare();

                client.get(url, new TextHttpResponseHandler() {

                    @Override
                    public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                        System.out.println("statusCode = " + statusCode + " result=" + responseString);
                    }

                    @Override
                    public void onSuccess(int statusCode, Header[] headers, String responseString) {

                        System.out.println("statusCode = " + statusCode + " result=" + responseString);
                        boolean isMain = Looper.myLooper() == Looper.getMainLooper();
                        System.out.println("isMain = " + isMain);
                    }
                });

                Looper.loop();//?????,????????quit(),?????????????
                System.out.println("url = " + url);//???????


            }
        }.start();

//        RequestHandle requestHandle = asyncHttpClient.get(context, url, textHttpResponseHandler);
//        requestHandle.cancel(true);


    }

    public void observable() {

        Observable<String> observable = Observable.from(new String[]{"1", "2", "3"});
        observable.subscribe(new Action1<String>() {
            @Override
            public void call(String s) {

            }
        });

    }


}
